package com.koron.order.perambulate.bean.excel;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.koron.bean.system.staff.vo.EamUser;
import com.koron.common.core.business.configsettings.utils.ConfigInfoTool;
import com.koron.common.core.config.ThreadLocalContext;
import com.koron.common.core.util.CodeTools;
import com.koron.order.overhaul.bean.dto.Equipment;
import com.koron.order.perambulate.bean.vo.LinePerambulateVo;
import com.koron.order.perambulate.service.LinePerambulateService;
import com.koron.order.risk.base.bean.po.LineRisk;
import com.koron.order.risk.base.excel.ExcelError;
import com.koron.order.risk.base.mapper.LineEquipmentMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.koron.ebs.mybatis.ADOConnection;
import org.koron.ebs.mybatis.SessionFactory;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @ClassName: PerambulateExcelListener
 * @Description:
 * @Date: 2023/2/1
 * @Author: 李一辰
 * @Version: 1.0
 **/
@Slf4j
@AllArgsConstructor
public class PerambulateExcelListener extends AnalysisEventListener<LinePerambulateExcel> {


    private LinePerambulateService linePerambulateService;

    private LinePerambulateConvertor linePerambulateConvertor;



    public PerambulateExcelListener(LinePerambulateService linePerambulateService) {
        this.linePerambulateService = linePerambulateService;
    }

    public EamUser getCurr(){return ThreadLocalContext.get();}
    // 每隔100条，然后清理list ，方便内存回收
    private static final int BATCH_COUNT = 100;
    // 要保存的数据
    private final List<LinePerambulateVo> LineRiskVOList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

    // 设备缓存
    private final Equipment rootEquipment = allLineEquipment();
    // 错误数据信息
    private final List<LinePerambulateExcel> errorRisk = new ArrayList<>();
    // 错误备注信息
    private final Map<Integer, ExcelError> excelErrors = new HashMap<>();

    private String getCurrDs() {
        return ThreadLocalContext.get().getCurrDs();
    }

    @Override
    public void invoke(LinePerambulateExcel data, AnalysisContext context) {
        LinePerambulateVo linePerambulateVo = fillData(data);
        if (linePerambulateVo == null) {
            return;
        }
        LineRiskVOList.add(linePerambulateVo);
        if (LineRiskVOList.size() >= BATCH_COUNT) {
            saveData();
            // 存储完成清理 list
            LineRiskVOList.clear();
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        log.info("所有数据解析完成！");
    }

    /**
     * 填充数据字段
     */
    private LinePerambulateVo fillData(LinePerambulateExcel data) {
        if (data == null) {
            return null;
        }

        //线路
        LinePerambulateVo linePerambulateVo = ExceltoVO(data);
        linePerambulateVo.setCreateName(getCurr().getName());
        linePerambulateVo.setCreateTime(new Date());
        String lineName = linePerambulateVo.getEquipmentName();
        if(lineName == null){
            fillError(data,0,"线路名称不能为空");
        }
        Equipment line = getLineByName(linePerambulateVo.getEquipmentName());
        if (line == null) {
            fillError(data, 0, "线路：" + linePerambulateVo.getEquipmentName() + "不存在");
            return null;
        }  else {
            linePerambulateVo.setId(CodeTools.getCode32());
        }

        // 塔段
        if (StrUtil.isEmpty(data.getTowerNumber())) {
            fillError(data, 1, "杆塔不能为空");
            return null;
        }
        Equipment tower = getTowerByNamesAndChildren(line.getName(), data.getTowerNumber(), line.getChildren());
        if (tower == null) {
            fillError(data, 1, "杆塔：" + data.getTowerNumber() + "不存在");
            return null;
        }  else {
            linePerambulateVo.setTowerNumber(data.getTowerNumber());
        }
        //数字校验
        boolean number1 = NumberUtil.isNumber(data.getClosestDistanceTower());
        boolean number2 = NumberUtil.isNumber(data.getLongitude());
        boolean number3 = NumberUtil.isNumber(data.getLatitude());
        if(!number1){
            fillError(data,4,"最近杆塔距离输入非数值型，不是整数或小数");
            return null;
        }
        linePerambulateVo.setClosestDistanceTower(data.getClosestDistanceTower());
        if(!number2){
            fillError(data,7,"经度输入非数值型，不是整数或小数");
            return null;
        }
        linePerambulateVo.setLongitude(data.getLongitude());
        if(!number3){
            fillError(data,8,"纬度输入非数值型，不是整数或小数");
            return null;
        }
        linePerambulateVo.setLatitude(data.getLatitude());
        //风险子类和风险关键字校验
        List<LineRisk> riskList = ADOConnection.runTask(getCurrDs(), linePerambulateService, "getRiskSubandKeyword", List.class);
        if(data.getRiskSub()== null)
        {
            fillError(data,5,"风险子类不能为空");
            return null;
        }
        boolean b = riskList.stream().anyMatch(i -> i.getRiskType().equals(data.getRiskSub()));
        if(!b){
            fillError(data,5,"风险子类不存在");
            return null;
        }
        linePerambulateVo.setRiskSub(data.getRiskSub());
        if(data.getRiskKeyword()== null)
        {
            fillError(data,6,"风险关键字不能为空");
            return null;
        }
        boolean b1 = riskList.stream().anyMatch(i -> i.getRiskKeyword().equals(data.getRiskKeyword()));
        if(!b1){
            fillError(data,6,"风险关键字不存在");
            return null;
        }
        linePerambulateVo.setRiskKeyword(data.getRiskKeyword());
        return linePerambulateVo;
    }

    private void saveData() {
        ADOConnection.runTask(getCurrDs(), linePerambulateService, "BatchInsert", Integer.class, LineRiskVOList);
        log.info("存储数据库成功！");
    }

    private void fillError(LinePerambulateExcel data, int collIndex, String tip) {
        errorRisk.add(data);
        ExcelError excelError = new ExcelError(errorRisk.size(), collIndex, tip);
        excelErrors.put(errorRisk.size()+1, excelError);
        log.error(tip);
    }


    private Equipment allLineEquipment() {
        // 1. 查询根设备
        Map<String, String> config = ConfigInfoTool.getConfigByCode("equipment", "line_root_device");
        String id = config.get("id");
        try (SessionFactory factory = new SessionFactory()) {
            factory.setDbEnv(getCurrDs());
            LineEquipmentMapper mapper = factory.getMapper(LineEquipmentMapper.class);
            Equipment root = mapper.getById(id);
            List<Equipment> equipmentList = mapper.selectSimpleLineEquipment(root.getLevelPath(), root.getLevel() + 3);
            // 线路设备
            Map<String, Equipment> lineEquipmentMap = new HashMap<>();
            for (Equipment equipment : equipmentList) {
                // 本身equipmentList就是有序的
                // 添加线路设备
                String parentId = equipment.getParentId();
                if (parentId.equals(root.getId())) {
                    if (root.getChildren() == null) {
                        root.setChildren(new ArrayList<>(Collections.singletonList(equipment)));
                    } else {
                        List<Equipment> children = root.getChildren();
                        children.add(equipment);
                    }
                    lineEquipmentMap.put(equipment.getId(), equipment);
                }

                // 添加杆塔
                if (lineEquipmentMap.containsKey(parentId)) {
                    Equipment parent = lineEquipmentMap.get(parentId);
                    if (parent.getChildren() == null) {
                        parent.setChildren(new ArrayList<>(Collections.singletonList(equipment)));
                    } else {
                        List<Equipment> children = parent.getChildren();
                        children.add(equipment);
                    }
                }
            }
            return root;
        }
    }

    private Equipment getLineByName(String name) {
        List<Equipment> children = rootEquipment.getChildren();
        List<Equipment> lines = children.stream().filter(e -> name.equals(e.getName())).collect(Collectors.toList());
        if (lines.isEmpty()) {
            return null;
        } else {
            return lines.get(0);
        }
    }
    private Equipment getTowerByNamesAndChildren(String parentName, String name, List<Equipment> children) {
        if(name.contains("塔")){
            List<Equipment> tower1 = children.stream().filter(i -> i.getName().equals(parentName + name )).collect(Collectors.toList());
            if (CollUtil.isEmpty(tower1)) {
                return null;
            }
            return tower1.get(0);
        }
        else{
            List<Equipment> tower2 = children.stream().filter(i -> i.getName().equals(parentName + name + "塔")).collect(Collectors.toList());
            if (CollUtil.isEmpty(tower2)) {
                return null;
            }
            return tower2.get(0);
        }
    }



    public List<LinePerambulateExcel> getErrorRisk() {
        return errorRisk;
    }

    public List<ExcelError> getExcelErrors() {
        return new ArrayList<>(excelErrors.values());
    }

    public LinePerambulateVo ExceltoVO(LinePerambulateExcel linePerambulateExcel){

        if(linePerambulateExcel == null){
            return new LinePerambulateVo();
        }
        LinePerambulateVo linePerambulateVo = new LinePerambulateVo();
        linePerambulateVo.setClosestDistanceLine(linePerambulateExcel.getClosestDistanceLine());
        linePerambulateVo.setEquipmentName(linePerambulateExcel.getEquipmentName());
        linePerambulateVo.setRemark(linePerambulateExcel.getRemark());
        linePerambulateVo.setRiskKeyword(linePerambulateExcel.getRiskKeyword());
        linePerambulateVo.setRiskLevel(linePerambulateExcel.getRiskLevel());
        linePerambulateVo.setRiskSub(linePerambulateExcel.getRiskSub());
        return linePerambulateVo;
    }
}
